// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/parser/ast/stmt.h>

namespace cantor::parser {
    std::unordered_map<int, const char *> TypeNameNumeric::TYPE_NAME_MAP = {
        {static_cast<int>(pb::ast::NumericType::NT_NONE), ""},
        {static_cast<int>(pb::ast::NumericType::NT_BOOL), "BOOL"},
        {static_cast<int>(pb::ast::NumericType::NT_INT), "INT32"},
        {static_cast<int>(pb::ast::NumericType::NT_INT8), "INT8"},
        {static_cast<int>(pb::ast::NumericType::NT_INT16), "INT16"},
        {static_cast<int>(pb::ast::NumericType::NT_INT32), "INT32"},
        {static_cast<int>(pb::ast::NumericType::NT_INT64), "INT64"},
        {static_cast<int>(pb::ast::NumericType::NT_INT128), "INT128"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT), "UINT32"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT8), "UINT8"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT16), "UINT16"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT32), "UINT32"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT64), "UINT64"},
        {static_cast<int>(pb::ast::NumericType::NT_UINT128), "UINT128"},
        {static_cast<int>(pb::ast::NumericType::NT_DECIMAL), "DECIMAL"},
        {static_cast<int>(pb::ast::NumericType::NT_F8), "FP8"},
        {static_cast<int>(pb::ast::NumericType::NT_F16), "FP16"},
        {static_cast<int>(pb::ast::NumericType::NT_F32), "FP32"},
        {static_cast<int>(pb::ast::NumericType::NT_F64), "FP64"}
    };


    nlohmann::ordered_json TypeStmt::to_json_impl() const {
        nlohmann::ordered_json j = StmtNode::to_json_impl();
        j["name"] = names[0].value;
        j["typeOid"] = typeOid;
        j["setof"] = setof;
        j["pct_type"] = pct_type;
        j["typename_type"] = pb::ast::TypeNameType_Name(typename_type);
        auto mods = nlohmann::ordered_json::array();
        for (auto i = 0; i < typmods.size(); i++) {
            auto mod = typmods[i];
            mods.push_back(mod->to_json());
        }
        j["typmods"] = mods;

        auto bounds = nlohmann::ordered_json::array();
        for (auto i = 0; i < array_bounds.size(); i++) {
            auto bound = array_bounds[i];
            bounds.push_back(bound->to_json());
        }
        j["array_bounds"] = bounds;
        return j;
    }

    nlohmann::ordered_json TypeNameGeneric::to_json() const {
        return TypeStmt::to_json_impl();
    }

    nlohmann::ordered_json TypeNameNumeric::to_json() const {
        return TypeStmt::to_json_impl();
    }

    const char *TypeNameNumeric::type_name(pb::ast::NumericType t) {
        auto it = TYPE_NAME_MAP.find(static_cast<int>(t));
        if (it == TYPE_NAME_MAP.end()) {
            return nullptr;
        }
        return it->second;
    }


    nlohmann::ordered_json TypeNameTimestamp::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["precision"] = pb::ast::TimeStampPrecision_Name(precision);
        return j;
    }

    nlohmann::ordered_json TypeNameDuration::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["precision"] = pb::ast::TimeStampPrecision_Name(precision);
        return j;
    }

    nlohmann::ordered_json TypeNameDateTime::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["precision"] = pb::ast::TimeStampPrecision_Name(precision);
        return j;
    }

    nlohmann::ordered_json TypeNameInterval::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["precision"] = pb::ast::TimeStampPrecision_Name(precision);
        return j;
    }

    nlohmann::ordered_json TypeNameJson::to_json() const {
        auto j = TypeStmt::to_json_impl();
        return j;
    }

    nlohmann::ordered_json TypeNameBitmap::to_json() const {
        auto j = TypeStmt::to_json_impl();
        return j;
    }

    nlohmann::ordered_json TypeNameTdigest::to_json() const {
        auto j = TypeStmt::to_json_impl();
        return j;
    }

    nlohmann::ordered_json TypeNameHll::to_json() const {
        auto j = TypeStmt::to_json_impl();
        return j;
    }

    nlohmann::ordered_json TypeNameString::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["charset"] = std::move(charset.to_string());
        j["collate"] = std::move(collate.to_string());
        return j;
    }

    nlohmann::ordered_json TypeNameMap::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["key"] = key->to_json();
        j["value"] = value->to_json();
        return j;
    }

    nlohmann::ordered_json TypeNameSet::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["key"] = key->to_json();
        return j;
    }

    nlohmann::ordered_json TypeNameTuple::to_json() const {
        auto j = TypeStmt::to_json_impl();
        auto types = nlohmann::ordered_json::array();
        for (auto i = 0; i < type_args.size(); i++) {
            types.push_back(type_args[i]->to_json());
        }
        j["type_args"] = types;
        return j;
    }

    nlohmann::ordered_json TypeNameUnion::to_json() const {
        auto j = TypeStmt::to_json_impl();
        auto types = nlohmann::ordered_json::array();
        for (auto i = 0; i < type_args.size(); i++) {
            nlohmann::ordered_json p;
            p["key"] = type_args[i]->name.to_string();
            p["type"] = type_args[i]->type->to_json();
            types.push_back(std::move(p));
        }
        j["type_args"] = types;
        return j;
    }

    nlohmann::ordered_json TypeNameStruct::to_json() const {
        auto j = TypeStmt::to_json_impl();
        auto types = nlohmann::ordered_json::array();
        for (auto i = 0; i < type_args.size(); i++) {
            nlohmann::ordered_json p;
            p["key"] = type_args[i]->name.to_string();
            p["type"] = type_args[i]->type->to_json();
            types.push_back(std::move(p));
        }
        j["type_args"] = types;
        return j;
    }

    nlohmann::ordered_json TypeNameProto::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["uri"] = uri->to_json();
        return j;
    }

    nlohmann::ordered_json TypeNameEnum::to_json() const {
        auto j = TypeStmt::to_json_impl();
        j["uri"] = uri->to_json();
        auto types = nlohmann::ordered_json::array();
        for (auto i = 0; i < type_args.size(); i++) {
            types.push_back(type_args[i]->to_json());
        }
        j["type_args"] = types;
        return j;
    }

} // namespace cantor::parser
